/*
* Copyright (c) Microsoft Corporation.  All Rights Reserved.
*
* Public Mock10 API
*/
#pragma once
#include "Mock10.h"

#include "MockFunction.h"

#pragma push_macro("Assert")
#undef Assert

#pragma push_macro("SEALED")
#undef SEALED

#if _MSC_VER >= 1400
# define SEALED sealed
#else
# define SEALED
#endif

namespace Mock10
{
    class ExternalMockTarget;

    template <typename TPrototype>
    class ExternalMockFunction;

    namespace Private
    {
        struct ExternalFunctionInfo;
        class ExternalMockFunctionInstanceBase;

        // The base class for ExternalMockFunctionImpl, which is owned by each ExternalMockFunction object that is created in the mocking process
        class __declspec(novtable) MOCK10_API ExternalMockFunctionBase abstract
        {
        public:
            ~ExternalMockFunctionBase();

            HRESULT GetStatus() const
            {
                return m_status.GetErrorCode();
            }

            const unsigned short* GetStatusMessage() const // Return unsigned short* here; otherwise we'd need to create both wchar_t* and __wchar_t* versions that return the value as an out parameter
            {
                return m_status.GetMessage();
            }

            HRESULT SetValue(const wchar_t* pszName, const unsigned char* pData, size_t dataSize);
            HRESULT GetValue(const wchar_t* pszName, unsigned char* pData, size_t dataSize);

            #if defined(MOCK10_FULL_BUILD)
            HRESULT SetValue(const __wchar_t* pszName, const unsigned char* pData, size_t dataSize);
            HRESULT GetValue(const __wchar_t* pszName, unsigned char* pData, size_t dataSize);
            #endif

        protected:
            ExternalMockFunctionBase();
            ExternalMockFunctionBase(const ExternalMockFunctionBase& other);

            MockStatus m_status;
            bool m_validateTarget;

            void Initialize(const ExternalMockTarget& externalMockTarget, void* pTargetFunction, void* pDetourFunction, void* pCreateFunction, const wchar_t* pszFilter);
            void InitializeFromQuery(const ExternalMockTarget& externalMockTarget, const wchar_t* pszTargetBinary, 
                                     const wchar_t* pszTargetQuery, void* pDetourFunction, unsigned long expectedMatchCount,
                                     void* pCreateFunction, const wchar_t* pszFilter, void* pTargetClass, void* pDetourShimPointer);
            void Set(void* pDetourFunction);
            void Clear();
            void SetFilter(const wchar_t* pszFilter);

            #if defined(MOCK10_FULL_BUILD)
            void Initialize(const ExternalMockTarget& externalMockTarget, void* pTargetFunction, void* pDetourFunction, void* pCreateFunction, const __wchar_t* pszFilter);
            void InitializeFromQuery(const ExternalMockTarget& externalMockTarget, const __wchar_t* pszTargetBinary, 
                                     const __wchar_t* pszTargetQuery, void* pDetourFunction, unsigned long expectedMatchCount,
                                     void* pCreateFunction, const __wchar_t* pszFilter, void* pTargetClass, void* pDetourShimPointer);
            void SetFilter(const __wchar_t* pszFilter);
            #endif
            
            void ValidateSignature(void* pFunction1, void* pFunction2, bool strictComparison = true);

        private:
            struct Impl;
            Impl* m_pImpl;

            ExternalMockFunctionBase& operator=(const ExternalMockFunctionBase&); // Not implemented
        };
        
        // A 'specialization'/derivative of a regular DetourFunction.  The purpose of this class is to act as a regular DetourFunction, but to add an additional first 
        // parameter to the callback that it calls when the DetourFunction gets invoked by the DetourShim.  
        // This is how we pass the ExternalMockFunction<TPrototype>::Info& into the detour function callback.
        template <typename TPrototype, typename TDetourPrototype, typename TInfo>
        class ExternalDetourFunction: public DetourFunctionImpl<TPrototype, TDetourPrototype, ExternalDetourFunction<TPrototype, TDetourPrototype, TInfo>>
        {
        template <typename TPrototype, typename TDetourFunction>
        friend struct DetourShim; // For access to detour 'Function' methods

        public:
            // Construct from a function pointer for the detour
            ExternalDetourFunction(TargetFunctionInfo& targetFunctionInfo, TDetourPrototype* pDetourFunction)
                : DetourFunctionImpl(targetFunctionInfo, pDetourFunction)
                , m_pExternalMockFunctionInstance(nullptr)
            {
            }

            void SetOwner(ExternalMockFunctionInstanceBase& owner)
            {
                WEX_ASSERT(!m_pExternalMockFunctionInstance, L"ExternalDetourFunction's owner was unexpectedly set more than once.");
                m_pExternalMockFunctionInstance = &owner;
            }

        private:
            #define EXTERNAL_DETOUR_NAMED_ARGS_0 
            #define EXTERNAL_DETOUR_NAMED_ARGS_1 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1
            #define EXTERNAL_DETOUR_NAMED_ARGS_2 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2
            #define EXTERNAL_DETOUR_NAMED_ARGS_3 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3
            #define EXTERNAL_DETOUR_NAMED_ARGS_4 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p4
            #define EXTERNAL_DETOUR_NAMED_ARGS_5 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p5
            #define EXTERNAL_DETOUR_NAMED_ARGS_6 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p6
            #define EXTERNAL_DETOUR_NAMED_ARGS_7 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p7
            #define EXTERNAL_DETOUR_NAMED_ARGS_8 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p8
            #define EXTERNAL_DETOUR_NAMED_ARGS_9 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p9
            #define EXTERNAL_DETOUR_NAMED_ARGS_10 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p10
            #define EXTERNAL_DETOUR_NAMED_ARGS_11 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p11
            #define EXTERNAL_DETOUR_NAMED_ARGS_12 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter13>::Result p12
            #define EXTERNAL_DETOUR_NAMED_ARGS_13 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter13>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter14>::Result p13
            #define EXTERNAL_DETOUR_NAMED_ARGS_14 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter13>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter14>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter15>::Result p14
            #define EXTERNAL_DETOUR_NAMED_ARGS_15 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter13>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter14>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter15>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter16>::Result p15
            #define EXTERNAL_DETOUR_NAMED_ARGS_16 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter13>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter14>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter15>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter16>::Result p15, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter17>::Result p16
            #define EXTERNAL_DETOUR_NAMED_ARGS_17 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter13>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter14>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter15>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter16>::Result p15, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter17>::Result p16, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter18>::Result p17
            #define EXTERNAL_DETOUR_NAMED_ARGS_18 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter13>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter14>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter15>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter16>::Result p15, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter17>::Result p16, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter18>::Result p17, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter19>::Result p18
            #define EXTERNAL_DETOUR_NAMED_ARGS_19 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter13>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter14>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter15>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter16>::Result p15, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter17>::Result p16, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter18>::Result p17, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter19>::Result p18, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter20>::Result p19

            #define EXTERNAL_DETOUR_ARGS_0 
            #define EXTERNAL_DETOUR_ARGS_1 , p1
            #define EXTERNAL_DETOUR_ARGS_2 , p1, p2
            #define EXTERNAL_DETOUR_ARGS_3 , p1, p2, p3
            #define EXTERNAL_DETOUR_ARGS_4 , p1, p2, p3, p4
            #define EXTERNAL_DETOUR_ARGS_5 , p1, p2, p3, p4, p5
            #define EXTERNAL_DETOUR_ARGS_6 , p1, p2, p3, p4, p5, p6
            #define EXTERNAL_DETOUR_ARGS_7 , p1, p2, p3, p4, p5, p6, p7
            #define EXTERNAL_DETOUR_ARGS_8 , p1, p2, p3, p4, p5, p6, p7, p8
            #define EXTERNAL_DETOUR_ARGS_9 , p1, p2, p3, p4, p5, p6, p7, p8, p9
            #define EXTERNAL_DETOUR_ARGS_10 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10
            #define EXTERNAL_DETOUR_ARGS_11 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11
            #define EXTERNAL_DETOUR_ARGS_12 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12
            #define EXTERNAL_DETOUR_ARGS_13 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13
            #define EXTERNAL_DETOUR_ARGS_14 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14
            #define EXTERNAL_DETOUR_ARGS_15 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15
            #define EXTERNAL_DETOUR_ARGS_16 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16
            #define EXTERNAL_DETOUR_ARGS_17 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17
            #define EXTERNAL_DETOUR_ARGS_18 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18
            #define EXTERNAL_DETOUR_ARGS_19 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19

            #define EXTERNAL_DETOUR_FUNCTION_METHOD(PARAMCOUNT) \
            typename WEX::Common::ParameterTypes<TDetourPrototype>::ReturnType Function(BUILD_VARIABLE_NAME(EXTERNAL_DETOUR_NAMED_ARGS_, PARAMCOUNT)) \
            { \
                WEX_ASSERT(m_detourFunction.IsValid(), L"ExternalDetourFunction is about to invoke an invalid functor."); \
                TInfo info(*this, m_pExternalMockFunctionInstance); \
                return (m_detourFunction)(info BUILD_VARIABLE_NAME(EXTERNAL_DETOUR_ARGS_, PARAMCOUNT)); \
            }

            // Builds out each Function(...) method that gets invoked by the DetourShim
            EXTERNAL_DETOUR_FUNCTION_METHOD(0)
            EXTERNAL_DETOUR_FUNCTION_METHOD(1)
            EXTERNAL_DETOUR_FUNCTION_METHOD(2)
            EXTERNAL_DETOUR_FUNCTION_METHOD(3)
            EXTERNAL_DETOUR_FUNCTION_METHOD(4)
            EXTERNAL_DETOUR_FUNCTION_METHOD(5)
            EXTERNAL_DETOUR_FUNCTION_METHOD(6)
            EXTERNAL_DETOUR_FUNCTION_METHOD(7)
            EXTERNAL_DETOUR_FUNCTION_METHOD(8)
            EXTERNAL_DETOUR_FUNCTION_METHOD(9)
            EXTERNAL_DETOUR_FUNCTION_METHOD(10)
            EXTERNAL_DETOUR_FUNCTION_METHOD(11)
            EXTERNAL_DETOUR_FUNCTION_METHOD(12)
            EXTERNAL_DETOUR_FUNCTION_METHOD(13)
            EXTERNAL_DETOUR_FUNCTION_METHOD(14)
            EXTERNAL_DETOUR_FUNCTION_METHOD(15)
            EXTERNAL_DETOUR_FUNCTION_METHOD(16)
            EXTERNAL_DETOUR_FUNCTION_METHOD(17)
            EXTERNAL_DETOUR_FUNCTION_METHOD(18)
            EXTERNAL_DETOUR_FUNCTION_METHOD(19)

            ExternalDetourFunction& operator=(const ExternalDetourFunction&); // Not implemented
            ExternalDetourFunction(const ExternalDetourFunction& other); // Not implemented

            ExternalMockFunctionInstanceBase* m_pExternalMockFunctionInstance;
        };

        // The base class for actual mock function instances that are loaded/instantiated in the target process
        // This class is never used directly by customers
        class __declspec(novtable) MOCK10_API ExternalMockFunctionInstanceBase abstract
        {
        public:
            virtual ~ExternalMockFunctionInstanceBase();
            virtual void Destroy() = 0;
            virtual void Clear() = 0;
            virtual void Set(const ExternalFunctionInfo& detourFunctionInfo) = 0;
            virtual void SetFilter(const wchar_t* pszFilter) = 0;

            HRESULT SetValue(const wchar_t* pszName, const unsigned char* pData, size_t dataSize);
            HRESULT GetValue(const wchar_t* pszName, unsigned char* pData, size_t dataSize);

            #if defined(MOCK10_FULL_BUILD)
            HRESULT SetValue(const __wchar_t* pszName, const unsigned char* pData, size_t dataSize);
            HRESULT GetValue(const __wchar_t* pszName, unsigned char* pData, size_t dataSize);
            #endif

        protected:
            explicit ExternalMockFunctionInstanceBase(const void* pExternalMockFunctionParameters, ExternalMockManager& mockManager);

            const TargetFunctionInfoArray& GetTargetFunctions() const;
            void* GetDetourFunction() const;
            void ThrowIfFailed(const MockStatus& mockStatus) const;
            void* LoadFunctionInfo(const ExternalFunctionInfo& functionInfo);
            const unsigned short* GetFilter() const; // Unsigned short so we only need to export one version

        private:
            struct Impl;
            Impl* m_pImpl;

            ExternalMockFunctionInstanceBase& operator=(const ExternalMockFunctionInstanceBase&); // Not implemented
            ExternalMockFunctionInstanceBase(const ExternalMockFunctionInstanceBase& other); // Not implemented
        };

        class ExternalMockManager;

        // The contained impl class for actual mock function and mock method instances that are loaded/instantiated in the target process
        // This class is never used directly by customers
        template <typename TMockImpl>
        class ExternalMockFunctionInstanceImpl: public ExternalMockFunctionInstanceBase
        {
        public:
            typedef typename TMockImpl::TDetourFunctionImpl TDetourFunctionImpl;

            void Clear()
            {
                m_mock.Clear();
                __super::ThrowIfFailed(m_mock.m_status);
            }

            void Set(const ExternalFunctionInfo& detourFunctionInfo)
            {
                m_mock.Set(reinterpret_cast<TMockImpl::TDetourPrototype*>(__super::LoadFunctionInfo(detourFunctionInfo)));
                __super::ThrowIfFailed(m_mock.m_status);
            }

            void SetFilter(const wchar_t* pszFilter)
            {
                m_mock.SetFilter(pszFilter);
                __super::ThrowIfFailed(m_mock.m_status);
            }

            virtual void Destroy()
            {
                delete this;
            }

            // Implement non-throwing new and its corresponding delete
            static void* operator new(size_t size)
            {
                return ::malloc(size);
            }

            static void operator delete(void* p, size_t)
            {
                ::free(p);
            }

        protected:
            explicit ExternalMockFunctionInstanceImpl(const void* pExternalMockFunctionInstanceParameters, ExternalMockManager& mockManager)
                : ExternalMockFunctionInstanceBase(pExternalMockFunctionInstanceParameters, mockManager)
                , m_mock(__super::GetTargetFunctions(), static_cast<TMockImpl::TDetourPrototype*>(__super::GetDetourFunction()))
            {
                m_mock.SetOwner(*this);

                const wchar_t* pszFilter = reinterpret_cast<const wchar_t*>(__super::GetFilter());
                if (pszFilter && *pszFilter && *pszFilter != L'\0')
                {
                    m_mock.SetFilter(pszFilter);
                }

                __super::ThrowIfFailed(m_mock.m_status);
            }

            ExternalMockFunctionInstanceImpl& operator=(const ExternalMockFunctionInstanceImpl&); // Not implemented
            ExternalMockFunctionInstanceImpl(const ExternalMockFunctionInstanceImpl& other); // Not implemented

            TMockImpl m_mock;
        };

        template <typename TPrototype, typename TDetourPrototype>
        class ExternalMockFunctionInstance: public ExternalMockFunctionInstanceImpl<MockFunction<TPrototype, 
                                                                                                 TDetourPrototype, 
                                                                                                 ExternalDetourFunction<TPrototype, 
                                                                                                                        TDetourPrototype, 
                                                                                                                        typename ExternalMockFunction<TPrototype>::Info>>>
        {
        template <typename TPrototype, typename TDetourPrototype, typename TMockImpl>
        friend class ExternalMockFunctionImpl;

        private:
            explicit ExternalMockFunctionInstance(const void* pExternalMockFunctionInstanceParameters, ExternalMockManager& mockManager)
                : ExternalMockFunctionInstanceImpl(pExternalMockFunctionInstanceParameters, mockManager)
            {
            }
        };

        template <typename TParameterTypes, unsigned short ParameterCount>
        struct ExternalDetourFunctionPrototypeImpl;
    
        #define EXTERNAL_DETOUR_FUNCTION_IMPL(PARAMCOUNT) \
        template <typename TPrototype> \
        struct ExternalDetourFunctionPrototypeImpl<TPrototype, PARAMCOUNT> \
        { \
        public: \
            typedef typename WEX::Common::ParameterTypes<TPrototype> TParameterTypes; \
            typedef typename TParameterTypes::ReturnType (Prototype) (typename ::Mock10::ExternalMockFunction<TPrototype>::Info& BUILD_VARIABLE_NAME(DETOUR_METHOD_NAMED_ARGS_, PARAMCOUNT)); \
        };

        EXTERNAL_DETOUR_FUNCTION_IMPL(0);
        EXTERNAL_DETOUR_FUNCTION_IMPL(1);
        EXTERNAL_DETOUR_FUNCTION_IMPL(2);
        EXTERNAL_DETOUR_FUNCTION_IMPL(3);
        EXTERNAL_DETOUR_FUNCTION_IMPL(4);
        EXTERNAL_DETOUR_FUNCTION_IMPL(5);
        EXTERNAL_DETOUR_FUNCTION_IMPL(6);
        EXTERNAL_DETOUR_FUNCTION_IMPL(7);
        EXTERNAL_DETOUR_FUNCTION_IMPL(8);
        EXTERNAL_DETOUR_FUNCTION_IMPL(9);
        EXTERNAL_DETOUR_FUNCTION_IMPL(10);
        EXTERNAL_DETOUR_FUNCTION_IMPL(11);
        EXTERNAL_DETOUR_FUNCTION_IMPL(12);
        EXTERNAL_DETOUR_FUNCTION_IMPL(13);
        EXTERNAL_DETOUR_FUNCTION_IMPL(14);
        EXTERNAL_DETOUR_FUNCTION_IMPL(15);
        EXTERNAL_DETOUR_FUNCTION_IMPL(16);
        EXTERNAL_DETOUR_FUNCTION_IMPL(17);
        EXTERNAL_DETOUR_FUNCTION_IMPL(18);
        EXTERNAL_DETOUR_FUNCTION_IMPL(19);
        EXTERNAL_DETOUR_FUNCTION_IMPL(20);

        // Converts a TPrototype into a version that takes an extra ExternalMockFunction<TPrototype>::Info& as the first parameter to the function
        template <typename TPrototype>
        struct ExternalDetourFunctionPrototype SEALED : public ExternalDetourFunctionPrototypeImpl<TPrototype, WEX::Common::ParameterTypes<TPrototype>::ParameterCount>
        {
        };

        template <typename TPrototype, typename TDetourPrototype, typename TInstance>
        class ExternalMockFunctionImpl SEALED : public Private::ExternalMockFunctionBase
        {
        public:
            ExternalMockFunctionImpl(const ExternalMockTarget& externalMockTarget, TPrototype* pTargetFunction)
            {
                Private::AutoDisableDetours disable;
                Initialize(externalMockTarget, ResolveFunctionPointer(pTargetFunction), NULL, NULL);
            }

            ExternalMockFunctionImpl(const ExternalMockTarget& externalMockTarget, TPrototype* pTargetFunction, const wchar_t* pszFilter)
            {
                Private::AutoDisableDetours disable;
                Initialize(externalMockTarget, ResolveFunctionPointer(pTargetFunction), NULL, pszFilter);
            }

            ExternalMockFunctionImpl(const ExternalMockTarget& externalMockTarget, TPrototype* pTargetFunction, TDetourPrototype* pDetourFunction)
            {
                Private::AutoDisableDetours disable;
                Initialize(externalMockTarget, ResolveFunctionPointer(pTargetFunction), ResolveFunctionPointer(pDetourFunction), NULL);
            }

            ExternalMockFunctionImpl(const ExternalMockTarget& externalMockTarget, TPrototype* pTargetFunction, TDetourPrototype* pDetourFunction, const wchar_t* pszFilter)
            {
                Private::AutoDisableDetours disable;
                Initialize(externalMockTarget, ResolveFunctionPointer(pTargetFunction), ResolveFunctionPointer(pDetourFunction), pszFilter);
            }

            ExternalMockFunctionImpl(const ExternalMockTarget& externalMockTarget, const wchar_t* pszTargetBinary, const wchar_t* pszTargetQuery, unsigned long expectedMatchCount = 1)
            {
                Private::AutoDisableDetours disable;
                InitializeFromQuery(externalMockTarget, pszTargetBinary, pszTargetQuery, NULL, NULL, expectedMatchCount);
            }

            ExternalMockFunctionImpl(const ExternalMockTarget& externalMockTarget, const wchar_t* pszTargetBinary, const wchar_t* pszTargetQuery, 
                                 const wchar_t* pszFilter, unsigned long expectedMatchCount = 1)
            {
                Private::AutoDisableDetours disable;
                InitializeFromQuery(externalMockTarget, pszTargetBinary, pszTargetQuery, NULL, pszFilter, expectedMatchCount);
            }

            ExternalMockFunctionImpl(const ExternalMockTarget& externalMockTarget, const wchar_t* pszTargetBinary, const wchar_t* pszTargetQuery, TDetourPrototype* pDetourFunction,
                                 unsigned long expectedMatchCount = 1)
            {
                Private::AutoDisableDetours disable;
                InitializeFromQuery(externalMockTarget, pszTargetBinary, pszTargetQuery, ResolveFunctionPointer(pDetourFunction), NULL, expectedMatchCount);
            }

            ExternalMockFunctionImpl(const ExternalMockTarget& externalMockTarget, const wchar_t* pszTargetBinary, const wchar_t* pszTargetQuery, TDetourPrototype* pDetourFunction, 
                                 const wchar_t* pszFilter, unsigned long expectedMatchCount = 1)
            {
                Private::AutoDisableDetours disable;
                InitializeFromQuery(externalMockTarget, pszTargetBinary, pszTargetQuery, ResolveFunctionPointer(pDetourFunction), pszFilter, expectedMatchCount);
            }

            void Set(TDetourPrototype* pDetourFunction)
            {
                Private::AutoDisableDetours disable;
                if (SUCCEEDED(m_status.GetErrorCode()))
                {
                    __super::Set(pDetourFunction);
                }

                #if !defined(NO_MOCK_THROW)
                if (FAILED(m_status.GetErrorCode()))
                {
                    Private::Throw::MockException(m_status);
                }
                #endif
            }

            // This version of Set is only here to help provide detailed compiler errors when attempting to set invalid detour functions
            static void Set(void*)
            {
                // The detour function specified does not match the expected signature.
                // Make sure that the detour function conforms to the following requirements:
                // 1. The return value and type/number of arguments must match that of the target function (with the exception of requirement 2 below).
                // 2. The first argument to the detour function must be an ExternalMockFunction<TPrototype>::Info&.  Make sure that the TPrototype value 
                //    specified for the ExternalMockFunction<TPrototype>::Info& exactly matches the TPrototype value of the function being mocked.
                //
                //    For example:
                //    
                //        void __stdcall TargeTFunction(int x, int y, int z);
                //    
                //        Correct:
                //            void MyDetourFunction(ExternalMockFunction<void __stdcall ()>::Info& info, int x, int y, int z);
                //
                //        Incorrect calling convention (should have specified __stdcall in the TPrototype): 
                //            void MyDetourFunction(ExternalMockFunction<void ()>::Info& info, int x, int y, int z);
                //
                //        Incorrect arguments (missing the initial argument ExternalMockFunction<void __stdcall ()>::Info&): 
                //            void MyDetourFunction(int x, int y, int z);
                //
                //        Incorrect arguments (missing int y): 
                //            void MyDetourFunction(ExternalMockFunction<void __stdcall ()>::Info& info, int x, int z);
                COMPILE_TIME_CHECK_V2(false,
                        "External detour function prototype mismatch; read the comments above this line for more information.", 
                        External_detour_function_prototype_mismatch_read_the_comments_above_this_line_for_more_information);
            }

            void Clear()
            {
                Private::AutoDisableDetours disable;
                if (SUCCEEDED(m_status.GetErrorCode()))
                {
                    __super::Clear();
                }

                #if !defined(NO_MOCK_THROW)
                if (FAILED(m_status.GetErrorCode()))
                {
                    Private::Throw::MockException(m_status);
                }
                #endif
            }

            void SetFilter(const wchar_t* pszFilter)
            {
                Private::AutoDisableDetours disable;
                if (SUCCEEDED(m_status.GetErrorCode()))
                {
                    __super::SetFilter(pszFilter);
                }

                #if !defined(NO_MOCK_THROW)
                if (FAILED(m_status.GetErrorCode()))
                {
                    Private::Throw::MockException(m_status);
                }
                #endif
            }

        private:
            ExternalMockFunctionImpl& operator=(const ExternalMockFunctionImpl&); // Not implemented

            void Initialize(const ExternalMockTarget& externalMockTarget, TPrototype* pTargetFunction, TDetourPrototype* pDetourFunction, const wchar_t* pszFilter)
            {
                if (FAILED(externalMockTarget.GetStatus()))
                {
                    // Don't bother doing anything with an invalid externalMockTarget
                    m_status.Set(externalMockTarget.GetStatus(), reinterpret_cast<const wchar_t*>(externalMockTarget.GetStatusMessage()));
                }
                else if (!pTargetFunction)
                {
                    // Don't bother doing anything with a NULL pTargetFunction
                    m_status.Set(E_POINTER);
                }
                else
                {
                    // Only perform target function validation in this path if explicitly requested
                    #if defined(VALIDATE_TARGET_FUNCTION_POINTERS)
                    ValidateTargetFunction(pTargetFunction);
                    #endif

                    ValidateDetourFunction(pDetourFunction);
                    if (SUCCEEDED(m_status.GetErrorCode()))
                    {
                        // Initialize in base class
                        __super::Initialize(externalMockTarget, pTargetFunction, pDetourFunction, &Create, pszFilter);
                    }
                }

                #if !defined(NO_MOCK_THROW)
                if (FAILED(m_status.GetErrorCode()))
                {
                    Private::Throw::MockException(m_status);
                }
                #endif
            }

            void InitializeFromQuery(const ExternalMockTarget& externalMockTarget, const wchar_t* pszTargetBinary, const wchar_t* pszTargetQuery, 
                                     TDetourPrototype* pDetourFunction, const wchar_t* pszFilter, unsigned long expectedMatchCount)
            {
                #if defined(NO_MOCK_VALIDATION)
                m_validateTarget = false;
                #endif

                if (FAILED(externalMockTarget.GetStatus()))
                {
                    // Don't bother doing anything with an invalid externalMockTarget
                    m_status.Set(externalMockTarget.GetStatus(), reinterpret_cast<const wchar_t*>(externalMockTarget.GetStatusMessage()));
                }
                else
                {
                    // Don't bother doing any work unless the detour is valid
                    ValidateDetourFunction(pDetourFunction);
                    if (SUCCEEDED(m_status.GetErrorCode()))
                    {
                        __super::InitializeFromQuery(externalMockTarget, pszTargetBinary, pszTargetQuery, pDetourFunction, expectedMatchCount, &Create, pszFilter,
                                                     Private::DetourShim<TPrototype, typename TInstance::TDetourFunctionImpl>::ClassPointer(),
                                                     Private::DetourShim<TPrototype, typename TInstance::TDetourFunctionImpl>::ShimPointer());
                    }
                }

                #if !defined(NO_MOCK_THROW)
                if (FAILED(m_status.GetErrorCode()))
                {
                    Private::Throw::MockException(m_status);
                }
                #endif
            }

            void ValidateTargetFunction(void* pTargetFunction)
            {
                UNREFERENCED_PARAMETER(pTargetFunction);

            #if !defined(NO_MOCK_VALIDATION)
                if (SUCCEEDED(m_status.GetErrorCode()))
                {
                    __super::ValidateSignature(pTargetFunction, Private::ResolveFunctionPointer(Private::DetourShim<TPrototype, typename Private::ExternalMockFunctionInstance<TPrototype, TDetourPrototype>::TDetourFunctionImpl>::ShimPointer()));
                }
            #endif
            }

            void ValidateDetourFunction(TDetourPrototype* pDetourFunction)
            {
                UNREFERENCED_PARAMETER(pDetourFunction);

                #if !defined(NO_MOCK_VALIDATION) && defined(VALIDATE_DETOUR_FUNCTIONS)
                // It is valid to create a detour with a null pDetourFunction
                if (pDetourFunction && SUCCEEDED(m_status.GetErrorCode()))
                {
                    // It is valid to have a detour whose calling convention is different than the target, because it will be invoked
                    // via a function pointer from within the Functor class -- it's the DetourShim which must have an identical calling convention to the target.
                    // So the check below simply validates that the detour function matches the signature that it claims to be.
                    __super::ValidateSignature(pDetourFunction, Private::ResolveFunctionPointer(Private::DetourShim<TDetourPrototype, Private::DetourFunction<TDetourPrototype>>::ShimPointer()), false);
                }
                #endif
            }

            template <typename TPrototype>
            static TPrototype* __stdcall ResolveFunctionPointer(TPrototype* pFunction)
            {
                return static_cast<TPrototype*>(Private::ResolveFunctionPointer(pFunction));
            }

            static Private::ExternalMockFunctionInstanceBase* __stdcall Create(const void* pExternalMockFunctionParameters, ExternalMockManager& mockManager)
            {
                // We implement operator new/delete in ExternalMockFunctionInstanceImpl, so we're guaranteed to not throw here
                return new TInstance(pExternalMockFunctionParameters, mockManager);
            }
        };
    } /* namespace Private */

    template <typename T>
    struct ExternalMockInfo
    {
        typedef typename T::Info Info;
    };

    // Public API used to inject and interact with an ExternalMockFunctionInstance in one or more target processes (specified by the ExternalMocktarget parameter to its constructors)
    template <typename TPrototype>
    class ExternalMockFunction SEALED
    {
    public:
        class Info;
        typedef typename Private::ExternalDetourFunctionPrototype<TPrototype>::Prototype TDetourPrototype;

        // This class is instantiated and passed as the first parameter to each detour function call in the target process
        class Info
        {
        friend class Private::ExternalDetourFunction<TPrototype, TDetourPrototype, Info>;
        typedef typename Private::ExternalMockFunctionInstance<TPrototype, TDetourPrototype>::TDetourFunctionImpl TDetourFunctionImpl;

        public:
            typename MockFunction<TPrototype, TDetourPrototype, TDetourFunctionImpl>::Target GetTarget() const
            {
                return MockFunction<TPrototype, TDetourPrototype, TDetourFunctionImpl>::Target(m_detourFunction.GetTarget());
            }

            template <typename TData>
            HRESULT SetValue(const wchar_t* pszName, const TData& value)
            {
                COMPILE_TIME_CHECK_V2(__is_pod(TData) || !__is_class(TData),
                        "TData arguments passed to SetValue must be PODs (plain old data types).", 
                        TData_arguments_passed_to_SetValue_must_be_PODs_aka_plain_old_data_types);

                return m_pExternalMockFunctionInstance->SetValue(pszName, reinterpret_cast<const unsigned char*>(&value), sizeof(TData));
            }

            template <typename TData>
            HRESULT GetValue(const wchar_t* pszName, __out TData& value)
            {
                COMPILE_TIME_CHECK_V2(__is_pod(TData) || !__is_class(TData),
                        "TData arguments passed to GetValue must be PODs (plain old data types).", 
                        TData_arguments_passed_to_GetValue_must_be_PODs_aka_plain_old_data_types);

                return m_pExternalMockFunctionInstance->GetValue(pszName, reinterpret_cast<unsigned char*>(&value), sizeof(TData));
            }

        private:
            Info(const TDetourFunctionImpl& detourFunction, Private::ExternalMockFunctionInstanceBase* pExternalMockFunctionInstance)
                : m_detourFunction(detourFunction)
                , m_pExternalMockFunctionInstance(pExternalMockFunctionInstance)
            {
            }

            Info(const Info&); // not implemented
            Info& operator=(Info&); // not implemented

            const TDetourFunctionImpl& m_detourFunction;
            Private::ExternalMockFunctionInstanceBase* m_pExternalMockFunctionInstance;
        };

        ExternalMockFunction(const ExternalMockTarget& externalMockTarget, TPrototype* pTargetFunction)
            : m_impl(externalMockTarget, pTargetFunction)
        {
        }

        ExternalMockFunction(const ExternalMockTarget& externalMockTarget, TPrototype* pTargetFunction, const wchar_t* pszFilter)
            : m_impl(externalMockTarget, pTargetFunction, pszFilter)
        {
        }

        ExternalMockFunction(const ExternalMockTarget& externalMockTarget, TPrototype* pTargetFunction, TDetourPrototype* pDetourFunction)
            : m_impl(externalMockTarget, pTargetFunction, pDetourFunction)
        {
        }

        ExternalMockFunction(const ExternalMockTarget& externalMockTarget, TPrototype* pTargetFunction, TDetourPrototype* pDetourFunction, const wchar_t* pszFilter)
            : m_impl(externalMockTarget, pTargetFunction, pDetourFunction, pszFilter)
        {
        }

        ExternalMockFunction(const ExternalMockTarget& externalMockTarget, const wchar_t* pszTargetBinary, const wchar_t* pszTargetQuery, unsigned long expectedMatchCount = 1)
            : m_impl(externalMockTarget, pszTargetBinary, pszTargetQuery, expectedMatchCount)
        {
        }

        ExternalMockFunction(const ExternalMockTarget& externalMockTarget, const wchar_t* pszTargetBinary, const wchar_t* pszTargetQuery, 
                             const wchar_t* pszFilter, unsigned long expectedMatchCount = 1)
            : m_impl(externalMockTarget, pszTargetBinary, pszTargetQuery, pszFilter, expectedMatchCount)
        {
        }

        ExternalMockFunction(const ExternalMockTarget& externalMockTarget, const wchar_t* pszTargetBinary, const wchar_t* pszTargetQuery, TDetourPrototype* pDetourFunction,
                             unsigned long expectedMatchCount = 1)
            : m_impl(externalMockTarget, pszTargetBinary, pszTargetQuery, pDetourFunction, expectedMatchCount)
        {
        }

        ExternalMockFunction(const ExternalMockTarget& externalMockTarget, const wchar_t* pszTargetBinary, const wchar_t* pszTargetQuery, TDetourPrototype* pDetourFunction, 
                             const wchar_t* pszFilter, unsigned long expectedMatchCount = 1)
            : m_impl(externalMockTarget, pszTargetBinary, pszTargetQuery, pDetourFunction, pszFilter, expectedMatchCount)
        {
        }

        void Set(TDetourPrototype* pDetourFunction)
        {
            m_impl.Set(pDetourFunction);
        }

        // This version of Set is only here to help provide detailed compiler errors when attempting to set invalid detour functions
        static void Set(void* p)
        {
            Private::ExternalMockFunctionImpl<TPrototype, TDetourPrototype, Private::ExternalMockFunctionInstance<TPrototype, TDetourPrototype>>::Set(p);
        }

        void Clear()
        {
            m_impl.Clear();
        }

        void SetFilter(const wchar_t* pszFilter)
        {
            m_impl.SetFilter(pszFilter);
        }

        HRESULT GetStatus() const
        {
            return m_impl.GetErrorCode();
        }

        const unsigned short* GetStatusMessage() const // Return unsigned short* here; otherwise we'd need to create both wchar_t* and __wchar_t* versions that return the value as an out parameter
        {
            return m_impl.GetMessage();
        }

        template <typename TData>
        HRESULT SetValue(const wchar_t* pszName, const TData& value)
        {
            COMPILE_TIME_CHECK_V2(__is_pod(TData) || !__is_class(TData),
                    "TData arguments passed to SetValue must be PODs (plain old data types).", 
                    TData_arguments_passed_to_SetValue_must_be_PODs_aka_plain_old_data_types);

            return m_impl.SetValue(pszName, reinterpret_cast<const unsigned char*>(&value), sizeof(TData));
        }

        template <typename TData>
        HRESULT GetValue(const wchar_t* pszName, __out TData& value)
        {
            COMPILE_TIME_CHECK_V2(__is_pod(TData) || !__is_class(TData),
                    "TData arguments passed to GetValue must be PODs (plain old data types).", 
                    TData_arguments_passed_to_GetValue_must_be_PODs_aka_plain_old_data_types);

            return m_impl.GetValue(pszName, reinterpret_cast<unsigned char*>(&value), sizeof(TData));
        }

    private:
        ExternalMockFunction& operator=(const ExternalMockFunction&); // Not implemented

        Private::ExternalMockFunctionImpl<TPrototype, TDetourPrototype, Private::ExternalMockFunctionInstance<TPrototype, TDetourPrototype>> m_impl;
    };

    // This template specialization helps 'guide' the compiler to the correct Mock::ExternalFunction overloads when function queries are specified
    template <>
    class ExternalMockFunction<const wchar_t> SEALED
    {
    typedef void TDetourPrototype;

    public:
        template <typename T>
        ExternalMockFunction(const T&, ...)
        {
            // Make sure to specify TPrototype in your call to Mock::ExternalFunction<TPrototype(pszTargetBinary, pszQuery, ...)
            COMPILE_TIME_CHECK_V2(false,
                    "You must explicitly specify a function prototype (via TPrototype) when issuing function queries.", 
                    You_must_explicitly_specify_TPrototype_when_issuing_function_queries);
        }
    };
} /* namespace Mock10 */

#pragma pop_macro("SEALED")
#pragma pop_macro("Assert")
